Skip to content

feat(expenses): add client-side sorting to expenses table#47

Open
BAVYASAKTHIVEL-21 wants to merge 3 commits into
rushikesh-bobade:mainfrom
BAVYASAKTHIVEL-21:feature/expenses-table-sorting
Open

feat(expenses): add client-side sorting to expenses table#47
BAVYASAKTHIVEL-21 wants to merge 3 commits into
rushikesh-bobade:mainfrom
BAVYASAKTHIVEL-21:feature/expenses-table-sorting

Conversation

@BAVYASAKTHIVEL-21

Copy link
Copy Markdown

Description

This adds sorting to the one-time expenses table. You can now click on the Date or Amount column header to sort by it, and clicking the same header again flips it between ascending and descending. There's a little arrow next to the header so you can tell which column is sorted and which way.

I set it to sort by Date (newest first) by default, since that's how the table already showed up before, so nothing looks different when the page first loads.

Related Issues

Closes #33

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code

@vercel

vercel Bot commented Jul 1, 2026

Copy link
Copy Markdown

@BAVYASAKTHIVEL-21 is attempting to deploy a commit to the participationcorner2025-8967's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added the ECSoC26 Required label for ECSOC Sentinel scoring label Jul 1, 2026
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

📝 Summary

The pull request introduces a sorting feature to the one-time expenses table. It adds a clickable header with sort indicators and aria-sort attributes for accessibility. The sorting is done using the useMemo hook to prevent unnecessary re-renders.

📂 Files Changed

  • app/blocks/expenses-tracker/one-time-expenses-table.module.css: Added new CSS classes for the sortable header and sort icons.
  • app/blocks/expenses-tracker/one-time-expenses-table.tsx: Introduced the sorting feature, including state management, event handling, and rendering of the sortable header.

🎭 Code Poem

Sorting headers, a new delight
Clickable and accessible, shining bright
Aria-sort and icons, a perfect pair
Making the table, more user-friendly to share

🚨 Bugs & Architectural Violations * The code uses `var(--color-text-muted)` and other CSS variables, which is acceptable since it's using Vanilla CSS Modules. * The `SortableHeader` component is properly placed inside the `OneTimeExpensesTable` component, and not in a separate file in the `app/components/` directory, which is correct according to the architecture rules. * However, the code does not include any explicit `role` attributes on the `th` elements, which could be added for better accessibility. * The `IconChevronUp`, `IconChevronDown`, and `IconSelector` components are used, but their accessibility is not explicitly handled. It's assumed that these icons are properly implemented with `aria-hidden` attributes. Looks solid, but minor accessibility improvements can be made.
💡 Suggestions & Best Practices * Consider adding `role="columnheader"` to the `th` elements for better accessibility. * Add `aria-hidden` attributes to the icon components to ensure they are properly handled by screen readers. * The `useMemo` hook is used correctly to prevent unnecessary re-renders, but it's worth considering using `useCallback` for the `handleSort` function to prevent it from being recreated on every render. * The code uses `var(--color-text-muted)` and other CSS variables, which is acceptable, but it's worth considering using a more explicit naming convention for the CSS variables to improve readability. * The `sortedExpenses` array is created using the `useMemo` hook, but it's worth considering using a more efficient sorting algorithm, such as `lodash.sortBy`, to improve performance.

@rushikesh-bobade

Copy link
Copy Markdown
Owner

Hey @BAVYASAKTHIVEL-21 , great work on the table sorting! The UI implementation and accessibility additions look fantastic.

However, we have an architectural conflict. We just merged PR #39, which introduced Server-Side Pagination to this exact table. Because the table is now paginated on the server (10 items at a time), we can no longer use client-side sorting with useState. If we do, it will only sort the 10 items on the current page instead of querying the database for the sorted data across all pages!

Requested Changes:

  1. Please pull the latest main branch to resolve the merge conflicts on expenses-tracker.tsx.
  2. Move your sortKey and sortDir state into URL Search Parameters (e.g., ?sort=amount&dir=desc) using useSearchParams.
  3. Update the loader function in app/routes/expenses-tracker.tsx to read those URL parameters and apply them to the Prisma orderBy clause on the server before it paginates!

Let me know if you need any help wiring up the Remix server-side sorting!

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

📝 Summary

The provided pull request diff introduces sorting functionality to the OneTimeExpensesTable component. It adds a clickable header with sort indicators and aria-sort attributes for accessibility. The sorting is done based on the "date" and "amount" columns, and the direction can be toggled between ascending and descending. The changes also update the loader function to include sorting parameters and the ExpensesTrackerPage component to pass the sorting information to the OneTimeExpensesTable component.

📂 Files Changed

  • app/blocks/expenses-tracker/one-time-expenses-table.module.css: Added styles for the sortable header button and sort icons.
  • app/blocks/expenses-tracker/one-time-expenses-table.tsx: Implemented the sorting functionality and updated the component to accept sorting information as props.
  • app/routes/expenses-tracker.tsx: Updated the loader function to include sorting parameters and the ExpensesTrackerPage component to pass the sorting information to the OneTimeExpensesTable component.

🎭 Code Poem

Sorting headers, a new delight
Click to toggle, day or night
Ascending or descending, the choice is mine
Making data management a breeze, all the time

🚨 Bugs & Architectural Violations * The `OneTimeExpensesTable` component does not handle the case where the `expenses` prop is `null` or `undefined`. It should add a null check to handle this scenario. * The `SortableHeader` component does not have a `role` attribute, which is required for accessibility. It should add a `role="columnheader"` attribute to the `th` element. * The `IconChevronUp`, `IconChevronDown`, and `IconSelector` components are not wrapped in a `span` element with an `aria-hidden` attribute, which is required for accessibility. It should add a `span` element with `aria-hidden="true"` to wrap these icons. * The `useMemo` hook is used to memoize the sorted expenses, but it does not handle the case where the `expenses` prop changes. It should add a dependency on the `expenses` prop to the `useMemo` hook.
💡 Suggestions & Best Practices * The `OneTimeExpensesTable` component can be optimized by using a more efficient sorting algorithm, such as the `stable` sorting algorithm provided by the `Array.prototype.sort()` method. * The `SortableHeader` component can be extracted into a separate component to improve reusability and maintainability. * The `ExpensesTrackerPage` component can be optimized by using a more efficient way to update the sorting information, such as using the `useReducer` hook instead of the `useState` hook. * The code can be improved by adding more comments and documentation to explain the purpose and behavior of each component and function.

@rushikesh-bobade

Copy link
Copy Markdown
Owner

Hey @BAVYASAKTHIVEL-21! Awesome job, you nailed the server-side URL sorting and Prisma integration!

There’s just a merge conflict right now because another contributor added an "edit/delete" feature to this exact same table while you were working. When you pull main to resolve it, just make sure you keep BOTH your sorting props (sort/dir) AND their editing prop (onEdit) on the <OneTimeExpensesTable> component.

Also, great catch by the AI bot—if you could add role="columnheader" to the th element in your SortableHeader, that'd be perfect. Let me know when the conflicts are cleared and I'll merge this right away!

(P.S. I noticed your commits are showing up as "Unverified". It looks like you're signing them locally but haven't uploaded your GPG public key to your GitHub account settings yet!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ECSoC26 Required label for ECSOC Sentinel scoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Column Sorting to Expenses Table

2 participants